home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / ed3_1_1 / part03 / edio.c next >
C/C++ Source or Header  |  1991-11-07  |  25KB  |  1,063 lines

  1. /*
  2.     These are functions of ed3 that do keyboard, mouse and file IO.
  3.  
  4. 10-22-91 chg YZ to ZY
  5. 10-21-91 fix to allow saving defaults!
  6. 10-20-91 fix to refresh after loading!
  7. 10-13-91 add tell_user_overflow() and tell_user_changes(), get_undo_bufsize()
  8.          add load_defaults() and save_defaults()
  9. 09-09-91 made handle_key() portable
  10. 09-04-91 chg load_data to call add_point, add_face
  11. 09-06-91 adapted to use coord instead of short
  12. */
  13.  
  14. #include "sysnogr.h"
  15.  
  16. /* Menu numbers */
  17. #define ME_PROJECT        0
  18. #define ME_EDIT            1
  19. #define ME_POLYHEDRA    2
  20. #define ME_SPECIAL        3
  21. #define ME_OPTIONS        4
  22.  
  23. /* Menu items numbers */
  24. #define MI_LOAD            0
  25. #define MI_SAVE            1
  26. #define MI_CLEAR        2
  27. /* --- 3 */
  28. #define MI_SAVE_DEF        4    /* save defaults */
  29. #define MI_ABOUT        5
  30. /* --- 6 */
  31. #define MI_QUIT            7
  32.  
  33. #define MI_CUT            0
  34. #define MI_COPY            1
  35. #define MI_PASTE        2
  36. #define MI_DUPLICATE    3
  37. #define MI_ERASE        4
  38. #define MI_SELECTALL    6
  39. #define MI_SELECTCON    7
  40. #define MI_DESELECTALL    8
  41. #define MI_POINTSONLY    10
  42. #define MI_FACESONLY    11
  43. #define MI_EXCLUSIVE    12
  44.  
  45. #define MI_TETRA        0
  46. #define MI_OCTA            1
  47. #define MI_CUBE            2
  48. #define MI_ICOSA        3
  49. #define MI_DODEC        4
  50. #define MI_DODEC_RHOMB    5
  51. #define MI_CUBOCTA        6
  52. /* --- 7 */
  53. #define MI_GLOBE        8
  54. #define MI_SURF_REV        9
  55.  
  56. #define MI_RESET_ZOOM    0
  57. #define MI_FREQUENCY    1
  58. #define MI_CONNECT        2
  59. #define MI_DUAL            3
  60. #define MI_UNFOLD        4
  61. #define MI_NORMALIZE    5
  62. #define MI_STELLATE        6
  63. #define MI_ORIGIN        7
  64. #define MI_SETCLOCK        8
  65.  
  66. char *errstring[ERRORS] =
  67. {
  68.   "Everything is Okay",
  69.   "There was nothing it that file",
  70.   "Can't open file",
  71.   "That's not the kind of file ED3 can read",
  72.   "Not enough memory",
  73.   "Not enough memory for points",
  74.   "Not enough memory for faces",
  75.   "Not enough memory for polygons",
  76.   "Bad face: face refers to non-existent point"
  77. };
  78.  
  79.  
  80. void handle_gadget(id)
  81. int id;
  82. {
  83.   switch (id)
  84.   {
  85.     case GID_ADD:        mode = M_ADDP; break;
  86.     case GID_DELETE:    mode = M_DELP; break;
  87.     case GID_SELECTOR:    mode = M_SELE; break;
  88.     case GID_MOVE:        mode = M_MOVP; break;
  89.     case GID_FACE:        mode = M_FACE; break;    /* new face */
  90.     case GID_POLY:        mode = M_POLY; break;    /* new polygon */
  91.     case GID_MORE:        break;
  92.     case GID_DEFACE:     mode = M_DEFA; deselect_all(); break;
  93.     case GID_DEPOLY:     mode = M_DEPO; deselect_all(); break;
  94.     case GID_MORE2:        break;
  95.     case GID_ROTATE:    mode = M_ROTA; break;
  96.     case GID_ROTP:        break;
  97.     case GID_ZOOM:        mode = M_ZOOM; break;
  98.     case GID_DIST:
  99.         mode = M_DIST;
  100.         if (!flags.display_dtool)
  101.         {
  102.             flags.display_dtool = 1;
  103.             toggle_menuitem(ME_OPTIONS, MI_DISTANCETOOL);
  104.             draw_distance_tool();
  105.         }
  106.         break;
  107.     case GID_GLUE:        mode = M_GLUE; break;
  108.     case GID_UNDO:        undo(); break;
  109.     case GID_REDO:        redo(); break;
  110.     case GID_XY:        dmode = DM_XY; gz = 0; break;
  111.     case GID_XZ:        dmode = DM_XZ; gy = 0; break;
  112.     case GID_ZY:        dmode = DM_ZY; gx = 0; break;
  113.     case GID_3D:        break;
  114.     case GID_color1:    colors.newface = 1; break;
  115.     case GID_color2:    colors.newface = 2; break;
  116.     case GID_color3:    colors.newface = 3; break;
  117.   }
  118.   switch (id)
  119.   {
  120.     case GID_XY:
  121.     case GID_XZ:
  122.     case GID_ZY:
  123.         convert_points();
  124.         refresh_all();
  125.   }
  126.   draw_bars();
  127. }
  128.  
  129.  
  130. void mouse_down(buttons)    /* what to do when a mouse button is pressed */
  131. char buttons;                /* 0 = first, 1 = second, 2 = double click with first */
  132. {
  133.     index nearest;    /* closest point to the cursor */
  134.  
  135.     convert_to_xyz(mx, my);
  136.  
  137.     switch(mode)    /* many mode need to operate on the selected point */
  138.     {
  139.         case M_DELP:
  140.         case M_SELE:
  141.         case M_DEFA:
  142.         case M_DEPO:
  143.         case M_FACE:
  144.         case M_POLY:
  145.         case M_MOVP:
  146.         case M_MORE:
  147.         case M_KMORE:
  148.         case M_DIST:
  149.         case M_GLUE:
  150.             if (buttons & 1)    /* second button */
  151.                 nearest = find_nearest_in_space(gx, gy, gz, -1);
  152.             else
  153.                 nearest = find_nearest_on_screen(mx, my, -1);
  154.     }
  155.     switch(mode)
  156.     {
  157.         case M_ADDP:
  158.             begin_operation();
  159.             draw_point(add_point(gx, gy, gz), colors.point);
  160.             end_operation();
  161.             break;
  162.         case M_DELP:
  163.             begin_operation();
  164.             del_point(nearest, 0, 0);
  165.             end_operation();
  166.             break;
  167.         case M_SELE:
  168.             toggle_select(buttons, nearest);
  169.             break;
  170.         case M_MOVP:
  171.             start_moving_point(buttons, nearest);
  172.             break;
  173.         case M_FACE: start_face(nearest); break;
  174.         case M_POLY: start_poly(nearest); break;
  175.         case M_MORE: add_segment(nearest); break;
  176.  
  177.         case M_DEFA: start_to_kill_face(nearest); break;
  178.         case M_DEPO: start_to_kill_poly(nearest); break;
  179.         case M_KMORE: kill_segment(nearest); break;
  180.  
  181.         case M_ROTA: set_rot_axis(gx, gy, gz); break;
  182.         case M_ROTP: rotate(); break;
  183.         case M_ZOOM: zoom(buttons); break;
  184.         case M_DIST: distance_tool(buttons, nearest); break;
  185.         case M_GLUE: glue(nearest); break;
  186.     }
  187.     show_counts();
  188. }
  189.  
  190.  
  191. void mouse_up()            /* what to do when the first button goes up */
  192. {
  193.     if (flags.moving_points) finish_move();
  194.     if (flags.drag_dtool)
  195.     {
  196. #if 0
  197.         draw_distance_tool();
  198. #endif
  199.         flags.drag_dtool = 0;
  200.     }
  201.     show_counts();
  202. }
  203.  
  204.  
  205. void update_movement(newx, newy)
  206. coord newx, newy;
  207. {
  208.   mx = newx;
  209.   my = newy;
  210.  
  211.   if (flags.in_edit_area)
  212.   {
  213.     /* have we moved out? */
  214.     if (mx <= edit_minx || my <= edit_miny)
  215.     {
  216.       flags.in_edit_area = 0;
  217.       enable_menus(TRUE);
  218.     }
  219.   }
  220.   else
  221.   {
  222.     /* have we moved in? */
  223.     if (mx > edit_minx && my > edit_miny)
  224.     {
  225.       flags.in_edit_area = 1;
  226.       enable_menus(FALSE);
  227.     }
  228.   }
  229.  
  230.   if (!flags.in_edit_area) return;
  231.  
  232.   /* erase stuff */
  233.   if (flags.crosshair) draw_hair();    /* Erase/Redraw crosshair */
  234.   if (flags.drag_dtool)
  235.     draw_distance_tool();    /* Erase/Redraw distance tool */
  236.   if (flags.moving_points)    /* If we are dragging some points */
  237.     toggle_dragged_points();    /* then erase them */
  238.  
  239.   /* allow the pointer to move */
  240.   convert_to_xyz(mx, my);
  241.   if (flags.show_coords) draw_coords(0);
  242.  
  243.   /* redraw stuff */
  244.   if (flags.moving_points)    /* If we are dragging some points */
  245.     toggle_dragged_points();    /* then redraw them */
  246.   if (flags.drag_dtool)
  247.   {
  248.     dtool_end[flags.which_end].x = gx;
  249.     dtool_end[flags.which_end].y = gy;
  250.     dtool_end[flags.which_end].z = gz;
  251.     draw_distance_tool();    /* Erase/Redraw distance tool */
  252.   }
  253.   if (flags.crosshair) draw_hair();            /* Erase/Redraw crosshair */
  254.   if (mode == M_ROTP)
  255.   {
  256.     draw_rot();                /* Erase angle */
  257.     convert_to_xy(axis.x, axis.y, axis.z);
  258.     rot_angle = atan2((double)(py-my), (double)(mx-px));
  259.     draw_rot();    /* Redraw angle */
  260.   }
  261. }
  262.  
  263.  
  264. void handle_key(key)
  265. short key;
  266. {
  267.     /* first, keys that work in all modes */
  268.  
  269.     switch(key)
  270.     {
  271.         case 27:    /* Esc */
  272.           if (!selected)
  273.             select_all();
  274.           else
  275.             deselect_all();
  276.           break;
  277.         case 'c':
  278.             flags.crosshair ^= 1;
  279.             toggle_menuitem(ME_OPTIONS, MI_CROSSHAIR);
  280.             draw_hair();
  281.             break;
  282.         case 'd':
  283.             toggle_menuitem(ME_OPTIONS, MI_DISTANCETOOL);
  284.             toggle_dtool();
  285.             break;
  286.         case 'm':
  287.             mode = M_MOVP;
  288.             deselect_all();
  289.             break;
  290.         case 'u': undo(); break;
  291.         case 'r': redo(); break;
  292.         case 8:
  293.             del_selected();
  294.             show_counts();    /* it's likely we've changed something */
  295.             break;
  296.         case 'x': flags.debug ^= 1; break;
  297.         case '8':
  298.             if (dmode == DM_XY) gz++;
  299.             if (dmode == DM_XZ) gy++;
  300.             if (dmode == DM_ZY) gx++;
  301.             if (flags.show_coords) draw_coords(0); break;
  302.         case '2':
  303.             if (dmode == DM_XY) gz--;
  304.             if (dmode == DM_XZ) gy--;
  305.             if (dmode == DM_ZY) gx--;
  306.             if (flags.show_coords) draw_coords(0); break;
  307.         case 'a': zoom(1); break;
  308.         case 'z': zoom(0); break;
  309.         case ' ':
  310.             convert_points();
  311.             refresh_all();
  312.             break;
  313.     }
  314. }
  315.  
  316.  
  317. void handle_menu(menunum, itemnum, flags)
  318. int menunum, itemnum, flags;
  319. {
  320.     switch (menunum)
  321.     {
  322.       case ME_PROJECT:
  323.         handle_project(itemnum); break;
  324.       case ME_EDIT:
  325.         handle_edit(itemnum, flags); break;
  326.       case ME_POLYHEDRA:
  327.         handle_polyhedra(itemnum); break;
  328.       case ME_SPECIAL:
  329.         handle_special(itemnum); break;
  330.       case ME_OPTIONS:
  331.         handle_options(itemnum, flags); break;
  332.     }
  333.     show_counts();    /* in case we've altered the number of points or faces */
  334. }
  335.  
  336.  
  337. void handle_project(itemnum)
  338. int itemnum;
  339. {
  340.     switch (itemnum)
  341.     {
  342.         case MI_LOAD:      load_request(); refresh_all(); break;
  343.         case MI_SAVE:      save_request(); break;
  344.         case MI_CLEAR:      new(); break;
  345.         case MI_SAVE_DEF: save_defaults(); break;
  346.         case MI_ABOUT:      about_help(); break;
  347.         case MI_QUIT:
  348.             if (changes)
  349.             {
  350.                 if (!tell_user_changes()) break;
  351.             }
  352.             sys_exit("");
  353.             break;
  354.     }
  355. }
  356.  
  357.  
  358. void handle_edit(itemnum, mflags)
  359. int itemnum;
  360. {
  361.   int value = mflags;
  362.  
  363.   switch (itemnum)
  364.   {
  365.     case MI_CUT: break;
  366.     case MI_COPY: break;
  367.     case MI_PASTE: break;
  368.     case MI_DUPLICATE: duplicate(!flags.points_only); break;
  369.     case MI_ERASE: del_selected(); break;
  370.     case MI_SELECTALL: select_all(); break;
  371.     case MI_SELECTCON: select_connected(-1); break;
  372.     case MI_DESELECTALL: deselect_all(); break;
  373.     case MI_POINTSONLY:    flags.points_only = value; break;
  374.     case MI_FACESONLY:    flags.faces_only = value; break;
  375.     case MI_EXCLUSIVE:    flags.exclusive_del = value; break;
  376.   }
  377. }
  378.  
  379.  
  380. void handle_polyhedra(itemnum)
  381. int itemnum;
  382. {
  383.   switch(itemnum)
  384.   {
  385.     case MI_GLOBE:
  386.       create_globe();
  387.       refresh_all();
  388.       break;
  389.     case 7:
  390.       break;
  391.     default:
  392.       create_poly(itemnum);
  393.       refresh_all();
  394.       break;
  395.   }
  396. }
  397.  
  398.  
  399. void handle_special(itemnum)
  400. int itemnum;
  401. {
  402.   char refresh = 0;
  403.  
  404.   switch (itemnum)
  405.   {
  406.     case MI_RESET_ZOOM:
  407.         reset_zoom();
  408.         convert_points();
  409.         refresh = 1;
  410.         break;
  411.     case MI_FREQUENCY:    frequency(); refresh = 1; break;
  412.     case MI_CONNECT:    break;
  413.     case MI_DUAL:        find_dual(); refresh = 1; break;
  414.     case MI_UNFOLD:        unfold(); break;
  415.     case MI_NORMALIZE:    normalize(); refresh = 1; break;
  416.     case MI_STELLATE:    stellate(); refresh = 1; break;
  417.     case MI_ORIGIN:     center_to_origin(); refresh = 1; break;
  418.     case MI_SETCLOCK:    set_clockwisdom(); break;
  419.   }
  420.   if (refresh) refresh_all();
  421. }
  422.  
  423.  
  424. void handle_options(itemnum, mflags)
  425. int itemnum;
  426. USHORT mflags;
  427. {
  428.   int value = mflags;
  429.  
  430.   switch (itemnum)
  431.   {
  432.     case MI_ASSUME_POLY:
  433.         flags.assume_poly = value;
  434.         break;
  435.     case MI_COORDS:
  436.         flags.show_coords = value;
  437.         draw_coords(!value);    /* if value is 0, erase */
  438.         break;
  439.     case MI_CROSSHAIR:
  440.         flags.crosshair = value;
  441.         draw_hair();
  442.         break;
  443.     case MI_DISTANCETOOL:
  444.         toggle_dtool();
  445.         break;
  446.     case MI_ROTATEALL:
  447.         flags.rotate_all = value;
  448.         break;
  449.     case MI_UNDOBUF:
  450.         flags.undo_active = value;
  451.         init_undo();
  452.         break;
  453.     case MI_UNDOBUFSIZE:
  454.         get_undo_bufsize();
  455.         break;
  456.   }
  457. }
  458.  
  459.  
  460. void add_all_menus()
  461. {
  462.   add_menu("Project");
  463.   add_menu("Edit");
  464.   add_menu("Polyhedra");
  465.   add_menu("Special");
  466.   add_menu("Options");
  467.  
  468.   add_menu_item(0, "Load   ", 0, 'O');
  469.   add_menu_item(0, "Save   ", 0, 'S');
  470.   add_menu_item(0, "Clear       ", 0, 0);
  471.   add_menu_item(0, "----", MO_NOTENABLED, 0);
  472.   add_menu_item(0, "Save defaults", 0, 0);
  473.   add_menu_item(0, "About/Help   ", 0, 0);
  474.   add_menu_item(0, "----", MO_NOTENABLED, 0);
  475.   add_menu_item(0, "Quit   ", 0, 'Q');
  476.  
  477.   add_menu_item(1, "Cut           ", MO_NOTENABLED, 'X');
  478.   add_menu_item(1, "Copy          ", MO_NOTENABLED, 'C');
  479.   add_menu_item(1, "Paste         ", MO_NOTENABLED, 'V');
  480.   add_menu_item(1, "Duplicate     ", 0, 'D');
  481.   add_menu_item(1, "Erase    (Backspace)", 0, 0);
  482.   add_menu_item(1, "----------    ", MO_NOTENABLED, 0);
  483.   add_menu_item(1, "Select All (Esc Esc)", 0, 0);
  484.   add_menu_item(1, "Select Connected    ", 0, 0);
  485.   add_menu_item(1, "Deselect All   (Esc)", 0, 0);
  486.   add_menu_item(1, "----------    ", MO_NOTENABLED, 0);
  487.   add_menu_item(1, "Points Only?     ", MO_TOGGLE, 0);
  488.   add_menu_item(1, "Faces/Polys Only?", MO_TOGGLE, 0);
  489.   add_menu_item(1, "Exclusive Delete?", MO_TOGGLE | MO_CHECKED, 0);
  490.  
  491.   add_menu_item(2, "Tetrahedron  ", 0, 0);
  492.   add_menu_item(2, "Octahedron   ", 0, 0);
  493.   add_menu_item(2, "Cube         ", 0, 0);
  494.   add_menu_item(2, "Icosahedron  ", 0, 0);
  495.   add_menu_item(2, "Dodecahedron ", 0, 0);
  496.   add_menu_item(2, " (rhombic)   ", 0, 0);
  497.   add_menu_item(2, "Cuboctahedron", 0, 0);
  498.   add_menu_item(2, "-------------", MO_NOTENABLED, 0);
  499.   add_menu_item(2, "Globe        ", 0, 0);
  500.   add_menu_item(2, "Surf. of Rev.", MO_NOTENABLED, 0);
  501.  
  502.   add_menu_item(3, "Reset Zoom ", 0, 'R');
  503.   add_menu_item(3, "Frequency  ", 0, 'F');
  504.   add_menu_item(3, "Connect 'em      ", MO_NOTENABLED, 0);
  505.   add_menu_item(3, "Find Dual  ", 0, 'D');
  506.   add_menu_item(3, "Unfold           ", MO_NOTENABLED, 0);
  507.   add_menu_item(3, "Normalize  ", 0, 'N');
  508.   add_menu_item(3, "Stellate         ", 0, 0);
  509.   add_menu_item(3, "Center -> Origin ", 0, 0);
  510.   add_menu_item(3, "Set Clockwisdom  ", 0, 0);
  511.  
  512.   add_menu_item(4, "Assume Polyhedron?    ", MO_TOGGLE | (flags.assume_poly  ? MO_CHECKED : 0), 0);
  513.   add_menu_item(4, "Display Coords?       ", MO_TOGGLE | (flags.show_coords  ? MO_CHECKED : 0), 0);
  514.   add_menu_item(4, "Display Crosshair? (c)", MO_TOGGLE | (flags.crosshair    ? MO_CHECKED : 0), 0);
  515.   add_menu_item(4, "Distance Tool?     (d)", MO_TOGGLE | (flags.display_dtool? MO_CHECKED : 0), 0);
  516.   add_menu_item(4, "Rotate Everything?    ", MO_TOGGLE | (flags.rotate_all   ? MO_CHECKED : 0), 0);
  517.   add_menu_item(4, "Undo Buffer Active?   ", MO_TOGGLE | (flags.undo_active  ? MO_CHECKED : 0), 0);
  518.   add_menu_item(4, "Set Undo Buffer Size  ", 0, 0);
  519.  
  520.   sys_attach_menus();
  521. }
  522.  
  523.  
  524. void add_all_gadgets()
  525. {
  526.   add_gadget("ADD", 0);
  527.   add_gadget("DELETE", 0);
  528.   add_gadget("SELECTOR", 0);
  529.   add_gadget("MOVE", 0);
  530.   add_gadget("FACE", 0);
  531.   add_gadget("POLY", 0);
  532.   add_gadget(" (more)", GF_NOSELECT);
  533.   add_gadget("DEFACE", 0);
  534.   add_gadget("DEPOLY", 0);
  535.   add_gadget(" (more)", GF_NOSELECT);
  536.   add_gadget("ROTATE", 0);
  537.   add_gadget("(rotate)", GF_NOSELECT);
  538.   add_gadget("ZOOM", 0);
  539.   add_gadget("DISTANCE", 0);
  540.   add_gadget("GLUE", 0);
  541.   add_gadget("UNDO", 0);
  542.   add_gadget("REDO", 0);
  543.   add_gadget("XY front", 0);
  544.   add_gadget("XZ top", 0);
  545.   add_gadget("ZY side ", 0);
  546.   add_gadget("> 3D <", GF_NOSELECT);
  547.   add_gadget("color1", 0);
  548.   add_gadget("color2", 0);
  549.   add_gadget("color3", 0);
  550.  
  551.   sys_refresh_gadgets();
  552. }
  553.  
  554.  
  555. save_data(fname)
  556. char *fname;
  557. {
  558.     uindex i, j;
  559.     FILE *fp;
  560.  
  561.     if (!points) return ERR_NOTHING;
  562.     fp = fopen(fname, "w");
  563.     if (!fp) return ERR_CANTOPEN;
  564.  
  565.     fprintf(fp, "#simple 3D file\n");
  566.     fprintf(fp, "points %d\n", points);
  567.     fprintf(fp, "faces %d\n", faces);
  568.     fprintf(fp, "polys %d\n", polys);
  569.  
  570.     /* save points */
  571.     fprintf(fp, "\n# points are stored as \"point X Y Z\"\n\n");
  572.     for (i = 0; i < points; i++)
  573. #if INTEGER
  574.         fprintf(fp, "point %d %d %d\n", point[i].x, point[i].y, point[i].z);
  575. #else
  576.         fprintf(fp, "point %lf %lf %lf\n", point[i].x, point[i].y, point[i].z);
  577. #endif
  578.  
  579.     /* save faces */
  580.     if (faces)
  581.     {
  582.         fprintf(fp, "\n# faces are stored as \"face p0 p1 p2 color\"\n\n");
  583.         for (i = 0; i < faces; i++)
  584.             fprintf(fp, "face %d %d %d %d\n",
  585.                 face[i].p[0], face[i].p[1], face[i].p[2], face[i].color);
  586.     }
  587.  
  588.     /* save polygons */
  589.     if (polys)
  590.     {
  591.         fprintf(fp, "\n# polygons are stored as \"poly N p1 ... pN color\"\n\n");
  592.         for (i = 0; i < polys; i++)
  593.         {
  594.             fprintf(fp, "poly %d ", poly[i].verts);
  595.             for (j = 0; j < poly[i].verts; j++)
  596.                 fprintf(fp, "%d ", poly[i].p[j]);
  597.             fprintf(fp, "%d\n", poly[i].color);
  598.         }
  599.     }
  600.     fprintf(fp, "\n");
  601.     fclose(fp);
  602.   return OKAY;
  603. }
  604.  
  605.  
  606. load_data(fname)
  607. char *fname;
  608. {
  609.     FILE *fp;
  610.     int j, k[MAX_EDGES];
  611.     coord x_lo, y_lo, z_lo,
  612.          x_hi, y_hi, z_hi,
  613.          x_size, y_size, z_size,
  614.          greatest;
  615.     char buf[128];        /* maximum line length */
  616.     uindex i;
  617. #if INTEGER
  618.     int x, y, z;
  619. #else
  620.     double x, y, z;
  621. #endif
  622.  
  623.   if (!(fp = fopen(fname, "r")))
  624.     return ERR_CANTOPEN;
  625.  
  626.   fgets(buf, 85, fp);    /* Read first line */
  627.   if (strncmp(buf, "#simple 3D file", 15))
  628.     return ERR_NOTED3;
  629.  
  630.     for (i = 0; i < 3; i++)
  631.     {
  632.         fgets(buf, 85, fp);
  633.         if (*buf == 0) break;
  634.         if (!strncmp(buf, "points ", 7))
  635.         {
  636.             sscanf(buf, "points %d\n", &j);
  637.  
  638.             /* see if this value is OK */
  639.             if (!j)
  640.             {
  641.                 fclose(fp);
  642.                 return ERR_NOTHING;
  643.             }
  644.             if (j >= MAX_POINTS)
  645.             {
  646.                 if (more_points(j + 100))
  647.                 {
  648.                     printf("unable to make room for %d points.\n", j);
  649.                     fclose(fp);
  650.                     return ERR_NOMEM_POINT;
  651.                 }
  652.             }
  653.         }
  654.         if (!strncmp(buf, "faces ", 7))
  655.         {
  656.             fscanf(fp, "faces %d\n", &j);
  657.             if (j >= MAX_FACES)
  658.             {
  659.                 if (more_faces(j + 100))
  660.                 {
  661.                     fclose(fp);
  662.                     return ERR_NOMEM_FACE;
  663.                 }
  664.             }
  665.         }
  666.         if (!strncmp(buf, "polys ", 7))
  667.         {
  668.             fscanf(fp, "polys %d\n", &j);
  669.             if (j >= MAX_POLYS)
  670.             {
  671.                 if (more_polys(j + 100))
  672.                 {
  673.                     fclose(fp);
  674.                     return ERR_NOMEM_POLY;
  675.                 }
  676.             }
  677.         }
  678.     }
  679.  
  680.     /* in case the object is much larger or smaller than the screen, we need
  681.         to adjust our scaling based on the bounding box of the data */
  682.     x_lo = y_lo = z_lo = x_hi = y_hi = z_hi = 0;
  683.     faces = points = polys = 0;
  684.  
  685.     while (fgets(buf, 85, fp) != NULL)
  686.     {
  687.         if (!strncmp(buf, "face ", 5))
  688.         {
  689.             sscanf(buf + 5, "%d %d %d %d", &k[0], &k[1], &k[2], &k[3]);
  690.             if (k[0] >= points || k[1] >= points || k[2] >= points)
  691.             {
  692.                 fclose(fp);
  693.                 return ERR_BADFACE;
  694.             }
  695.             add_face0(k[0], k[1], k[2], k[3]);
  696.         }
  697.         else if (!strncmp(buf, "poly ", 5))
  698.         {
  699.             sscanf(buf + 5, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
  700.                 k+0, k+1, k+2, k+3, k+4, k+5, k+6, k+7, k+8, k+9,
  701.                 k+10, k+11, k+12, k+13, k+14, k+15, k+16, k+17, k+18, k+19, k+20);
  702.             allocate_poly(k[0], k[k[0]+1]);
  703.             for (i = 0; i < k[0]; i++)
  704.                 poly[polys].p[i] = k[i+1];
  705.             finish_poly(1);
  706.         }
  707.         else if (!strncmp(buf, "point ", 6))
  708.         {
  709. #if INTEGER
  710.             sscanf(buf + 6, "%d %d %d", &x, &y, &z);
  711. #else
  712.             sscanf(buf + 6, "%lf %lf %lf", &x, &y, &z);
  713. #endif
  714.             if (x < x_lo) x_lo = x;
  715.             if (x > x_hi) x_hi = x;
  716.             if (y < y_lo) y_lo = y;
  717.             if (y > y_hi) y_hi = y;
  718.             if (z < z_lo) z_lo = z;
  719.             if (z > z_hi) z_hi = z;
  720.             add_point0(x, y, z);
  721.         }
  722.         else if (*buf && *buf != '#' && *buf != '\n')
  723.         {
  724.             printf("Don't understand line: %s", buf);
  725.         }
  726.     }
  727.  
  728.     x_size = max(-x_lo, x_hi);    /* since coordinates are always centered */
  729.     y_size = max(-y_lo, y_hi);
  730.     z_size = max(-z_lo, z_hi);
  731.      greatest = max(x_size, y_size);
  732.     greatest = max(greatest, z_size);
  733.  
  734.     /* scale = units per pixel.  Here, "greatest" is the most units
  735.         that half the screen must accomodate */
  736.     SCALE = (double)greatest / (double)(symax >> 1) * 1.1;
  737.  
  738.     fclose(fp);
  739.     convert_points();
  740.     return OKAY;
  741. }
  742.  
  743.  
  744. void get_undo_bufsize()
  745. {
  746.     long new_ab = act_buf;
  747.     long new_ob = op_buf;
  748.     int go = 1, ok = 1, event;
  749.     int id;
  750.     long data;
  751.  
  752.     sys_window(34, 4, "Set Undo Buffer Size");
  753.     sys_movecur(7,0);
  754.     sys_say_text("Size in bytes:");
  755.     sys_get_long(new_ab, 1);
  756.     sys_movecur(1,1);
  757.     sys_say_text("Maximum undo levels:");
  758.     sys_get_long(new_ob, 2);
  759.     sys_movecur(7,2);
  760.     sys_boolean(" OK ", 3);
  761.     sys_movecur(17,2);
  762.     sys_boolean("Cancel", 4);
  763.     sys_activate(1);
  764.  
  765.     while (go)
  766.     {
  767.         event = sys_read_event(&id, &data);
  768.         switch (event)
  769.         {
  770.         case EV_CANCEL:
  771.             go = 0;
  772.             break;
  773.         case EV_CHECKINT:
  774. /*            printf("checkint gadget %d, data %ld\n", id, data);    */
  775.         case EV_HITRETURN:
  776. /*            if (event == EV_HITRETURN) printf("hit return on gadget %d, data %ld\n", id, data); */
  777.             if (id == 1)
  778.             {
  779.                 if (data > 32000) data = 32000;
  780.                 if (data < 1000) data = 1000;
  781.                 new_ab = data;
  782.                 if (event == EV_HITRETURN) sys_activate(2);
  783.             }
  784.             if (id == 2)
  785.             {
  786.                 if (data > 2000) data = 2000;
  787.                 if (data < 10) data = 10;
  788.                 new_ob = data;
  789.                 if (event == EV_HITRETURN) { go = 0; ok = 1; }
  790.             }
  791.             break;
  792.         case EV_HITBUTTON:
  793. /*            printf("hit button on gadget %d, data %ld\n", id, data); */
  794.             if (id == 3) { go = 0; ok = 1; }
  795.             else { go = 0; ok = 0; }
  796.             break;
  797.         }
  798.     }
  799.     if (ok)
  800.     {
  801.         act_buf = new_ab;
  802.         op_buf = new_ob;
  803.     }
  804.     sys_close_window();
  805. }
  806.  
  807.  
  808. /* Tell the user that the requested operation will overflow the undo buffer. */
  809. /* Returns TRUE if the user decides to turn off undo and proceed anyway. */
  810.  
  811. int tell_user_overflow()
  812. {
  813.     int id, event;
  814.     long data;
  815.  
  816.     sys_window(45, 6, "Warning!");
  817.     sys_movecur(0,0);
  818.     sys_say_text("The operation you requested will overflow");
  819.     sys_movecur(0,1);
  820.     sys_say_text("the undo buffer.  Do you wish to turn undo");
  821.     sys_movecur(0,2);
  822.     sys_say_text("off and proceed, or cancel the operation?");
  823.     sys_movecur(1,4);
  824.     sys_boolean("Turn off and proceed", 1);
  825.     sys_say_text("  ");
  826.     sys_boolean("Cancel operation", 2);
  827.  
  828.     while (1)
  829.     {
  830.         event = sys_read_event(&id, &data);
  831.         switch (event)
  832.         {
  833.             case EV_HITBUTTON:
  834.                 if (id == 1)
  835.                 {
  836.                     flags.undo_active = 0;
  837.                     toggle_menuitem(ME_OPTIONS, MI_UNDOBUF);
  838.                     init_undo();
  839.                     sys_close_window();
  840.                     return 1;
  841.                 }
  842.             case EV_CANCEL:
  843.                 sys_close_window();
  844.                 return 0;    /* cancel operation */
  845.                 break;
  846.         }
  847.     }
  848. }
  849.  
  850.  
  851. /* Warn the user that there are unsaved changed */
  852. /* returns TRUE if the user say its OK to continue */
  853.  
  854. int tell_user_changes()
  855. {
  856.     char buf[20];
  857.     int go = 1, ok = 1, event;
  858.     int id;
  859.     long data;
  860.  
  861.     sys_window(37, 5, "Warning: Unsaved Changes!");
  862.     sys_movecur(1,0);
  863.     sys_say_text("You have made");
  864.     sprintf(buf, " %d ", changes);
  865.     sys_say_text(buf);
  866.     sys_say_text("unsaved ");
  867.     sys_say_text((changes < -1 || changes > 1) ? "changes." : "change.");
  868.     sys_movecur(1,1);
  869.     sys_say_text((changes < -1 || changes > 1) ? "They" : "It");
  870.     sys_say_text(" will be lost if you continue!");
  871.  
  872.     sys_movecur(4,3);
  873.     sys_boolean("OK - continue", 1);
  874.     sys_movecur(20,3);
  875.     sys_boolean("Cancel!", 2);
  876.  
  877.     while (go)
  878.     {
  879.         event = sys_read_event(&id, &data);
  880.         switch (event)
  881.         {
  882.         case EV_HITBUTTON:
  883.             if (id == 1) { go = 0; ok = 1; break; }
  884.         case EV_CANCEL:
  885.             go = 0;
  886.             ok = 0;
  887.             break;
  888.         }
  889.     }
  890.     sys_close_window();
  891.     return (ok);
  892. }
  893.  
  894.  
  895. /* Tell the user about ed3, and provide a little help. */
  896.  
  897. void about_help()
  898. {
  899.     int go = 1, ok = 1, event;
  900.     int id;
  901.     long data;
  902.  
  903.     sys_window(59, 13, "About ED3 - and some Help");
  904.     sys_movecur(0,0);
  905.     sys_say_text("ED3 is a 3D object editor placed in the public domain by");
  906.     sys_movecur(0,1);
  907.     sys_say_text("its author, Ben Discoe.  That means I didn't copyright it");
  908.     sys_movecur(0,2);
  909.     sys_say_text("and neither can you.  Information should be free, y'all.");
  910.     sys_movecur(0,3);
  911. #if INTEGER
  912.     sys_say_text("This is the integer version.  A floating-point version");
  913. #else
  914.     sys_say_text("This is the floating-point version.  An integer version");
  915. #endif
  916.     sys_movecur(0,4);
  917.     sys_say_text("is also available.  The source is freely available.");
  918.     sys_movecur(0,5);
  919.     sys_say_text("\"Faces\" refer to triangles, and \"Polys\" refer to");
  920.     sys_movecur(0,6);
  921.     sys_say_text("polygons with more than 3 sides.  This distinction is made");
  922.     sys_movecur(0,7);
  923.     sys_say_text("for reasons of efficiency.  Undo/Redo is available and is");
  924.     sys_movecur(0,8);
  925.     sys_say_text("limited only by the amount of memory you give it.");
  926.     sys_movecur(0,9);
  927.     sys_say_text("To learn the special features, experiment!");
  928.  
  929.     sys_movecur(12,11);
  930.     sys_boolean(" OK ", 1);
  931.     sys_movecur(28,11);
  932.     sys_boolean("Keyboard Shortcuts", 2);
  933.  
  934.     while (go)
  935.     {
  936.         event = sys_read_event(&id, &data);
  937.         switch (event)
  938.         {
  939.         case EV_HITBUTTON:
  940.             if (id == 2) { go = 0; ok = 0; break; }
  941.         case EV_CANCEL:
  942.             go = 0;
  943.             ok = 1;
  944.             break;
  945.         }
  946.     }
  947.     sys_close_window();
  948.     if (ok) return;
  949.  
  950.     sys_window(57, 6, "Keyboard Shortcuts");
  951.     sys_movecur(0,0);
  952.     sys_say_text(" c - toggle crosshair        Esc - deselect/select All");
  953.     sys_movecur(0,1);
  954.     sys_say_text(" d - toggle distance-tool      a - zoom in");
  955.     sys_movecur(0,2);
  956.     sys_say_text(" m - Move mode                 z - zoom out");
  957.     sys_movecur(0,3);
  958.     sys_say_text(" u - undo              backspace - kill selected");
  959.     sys_movecur(0,4);
  960.     sys_say_text(" r - redo              space bar - full refresh");
  961.     sys_movecur(22,5);
  962.     sys_boolean(" OK ", 1);
  963.  
  964.     go = 1;
  965.     while (go)
  966.     {
  967.         event = sys_read_event(&id, &data);
  968.         switch (event)
  969.         {
  970.         case EV_HITBUTTON:
  971.         case EV_CANCEL:
  972.             go = 0;
  973.             break;
  974.         }
  975.     }
  976.     sys_close_window();
  977. }
  978.  
  979.  
  980. void save_request()
  981. {
  982.   char *fname;
  983.   int status;
  984.  
  985.   fname = sys_file_requestor("Save 3D file", "*.3d");
  986.   if (! *fname) return;
  987.  
  988.   if (status = save_data(fname))
  989.     SimpleRequest("Problem saving: %s.", errstring[status]);
  990. }
  991.  
  992.  
  993. void load_request()
  994. {
  995.   char *fname;
  996.   int status;
  997.  
  998.   fname = sys_file_requestor("Load 3D file", "*.3d");
  999.   if (! *fname) return;
  1000.  
  1001.   if (status = load_data(fname))
  1002.     SimpleRequest("Problem loading: %s.", errstring[status]);
  1003. }
  1004.  
  1005.  
  1006. save_defaults()
  1007. {
  1008.     FILE *fp;
  1009.  
  1010.     fp = fopen("ed3-defs", "w");
  1011.     if (!fp) return ERR_CANTOPEN;
  1012.  
  1013.     fprintf(fp, "%d ", flags.assume_poly);
  1014.     fprintf(fp, "%d ", flags.display_dtool);
  1015.     fprintf(fp, "%d ", flags.show_coords);
  1016.     fprintf(fp, "%d ", flags.crosshair);
  1017.     fprintf(fp, "%d ", flags.rotate_all);
  1018.     fprintf(fp, "%d ", flags.undo_active);
  1019.     fprintf(fp, "%d ", act_buf);
  1020.     fprintf(fp, "%d ", op_buf);
  1021.  
  1022.     fclose(fp);
  1023.     return OKAY;
  1024. }
  1025.  
  1026.  
  1027. load_defaults()
  1028. {
  1029.     FILE *fp;
  1030.     int i1, i2, i3, i4;
  1031.  
  1032.     fp = fopen("ed3-defs", "r");
  1033.     if (!fp) return ERR_CANTOPEN;
  1034.  
  1035.     /* we must scanf indirectly because the destination variables may
  1036.         not be ints */
  1037.  
  1038.     fscanf(fp, "%d ", &i1);
  1039.     fscanf(fp, "%d ", &i2);
  1040.     fscanf(fp, "%d ", &i3);
  1041.     fscanf(fp, "%d ", &i4);
  1042.  
  1043.     flags.assume_poly = i1;
  1044.     flags.display_dtool = i2;
  1045.     flags.show_coords = i3;
  1046.     flags.crosshair = i4;
  1047.  
  1048.     fscanf(fp, "%d ", &i1);
  1049.     fscanf(fp, "%d ", &i2);
  1050.     fscanf(fp, "%d ", &i3);
  1051.     fscanf(fp, "%d ", &i4);
  1052.  
  1053.     flags.rotate_all = i1;
  1054.     flags.undo_active = i2;
  1055.     act_buf = i3;
  1056.     op_buf = i4;
  1057.  
  1058.     fclose(fp);
  1059.     return OKAY;
  1060. }
  1061.  
  1062.  
  1063.